package com.hzw.saas.service.user.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.product.ILicenseUserService;
import com.hzw.saas.api.property.IPropertyService;
import com.hzw.saas.api.property.enmus.SysDictKeyEnum;
import com.hzw.saas.api.property.enmus.SysDictModuleEnum;
import com.hzw.saas.api.user.*;
import com.hzw.saas.api.user.bo.*;
import com.hzw.saas.api.user.export.UserRegisterBO;
import com.hzw.saas.api.user.query.*;
import com.hzw.saas.common.config.exception.DefaultSaasException;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.config.util.PageUtils;
import com.hzw.saas.common.config.util.SpringContextUtils;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.ObjFieldUtil;
import com.hzw.saas.common.util.SnowFlakeUtil;
import com.hzw.saas.common.util.enums.AssertEnum;
import com.hzw.saas.common.util.enums.SortEnum;
import com.hzw.saas.service.user.mapper.CustomerMapper;
import com.hzw.saas.service.user.model.Customer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zzl
 * @since 04/03/2021
 */
@Service("customerServiceImpl")
@RequiredArgsConstructor
@Slf4j
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements ICustomerService, IService<Customer> {

    @Resource(name = IPropertyService.SYS_DICT_BEAN)
    private IPropertyService<SysDictKeyEnum> propertyService;

    @Resource(name = "userAccountServiceImpl")
    private IUserAccountService userAccountService;
    @Resource(name = "customerLevelServiceImpl")
    private ICustomerLevelService customerLevelService;
    @Resource(name = "licenseUserServiceImpl")
    private ILicenseUserService licenseUserService;
    @Resource(name = "staffServiceImpl")
    private IStaffService staffService;
    @Resource(name = "customerRefServiceImpl")
    private ICustomerRefService customerRefService;
    @Resource
    private IUserRightsService userRightsService;
    @Resource(name = "userWeTripartiteService")
    private IUserTripartiteService userTripartiteService;


    @Override
    public boolean existCustomer(CustomerGetQuery query, AssertEnum throwOnEnum) {
        return this.existCustomer(query, false, throwOnEnum);
    }

    @Override
    public CustomerBO getCustomerById(String pid) {
        if (StrUtil.isBlank(pid))
            return null;
        Customer customer = this.getById(pid);
        return MapperUtil.nf().map(customer, CustomerBO.class);
    }

    @Override
    public CustomerBO getCustomerDetailById(String pid) {
        Customer customer = this.getById(pid);
        if (Objects.isNull(customer))
            return null;
        CustomerBO bo = MapperUtil.nf().map(customer, CustomerBO.class);
        this.setProperties(ListUtil.toList(bo));
        return bo;
    }

    @Override
    public CustomerBO getCustomerByNo(String customerNo) {
        if (StringUtils.isBlank(customerNo))
            return null;
        Customer customer = this.lambdaQuery().eq(Customer::getCustomerNo, customerNo).one();
        return MapperUtil.nf().map(customer, CustomerBO.class);
    }

    @Override
    public CustomerBO getCustomerByUserId(String userId) {
        if (StringUtils.isBlank(userId))
            return null;
        Customer customer = this.lambdaQuery().eq(Customer::getUserId, userId).one();
        return MapperUtil.nf().map(customer, CustomerBO.class);
    }

    private boolean existCustomer(CustomerGetQuery query, boolean update, AssertEnum throwOnEnum) {
        if (ObjFieldUtil.isAllNullFields(query, ObjFieldUtil.ConvertNull.BLANK)) {
            return false;
        }
        if (!update && StrUtil.isNotBlank(query.getPid())) {
            int count = this.lambdaQuery().eq(Customer::getPid, query.getPid()).count();
            AssertUtil.assertThrow("客户信息已存在：" + query.getPid(), count > 0 && Objects.equals(throwOnEnum, AssertEnum.NOT_FOUND));
            AssertUtil.assertThrow("客户信息不存在：" + query.getPid(), count == 0 && Objects.equals(throwOnEnum, AssertEnum.FOUND));
            if (count > 0)
                return true;
        }
        AssertUtil.assertThrow("更新时ID不可为空", update && StrUtil.isBlank(query.getPid()));

        Integer count = this.lambdaQuery().ne(update, Customer::getPid, query.getPid())
            .eq(StrUtil.isBlank(query.getUserId()), Customer::getUserId, query.getUserId())
            .or().eq(StrUtil.isBlank(query.getUserName()), Customer::getUserName, query.getUserName())
            .or().eq(StrUtil.isBlank(query.getCustomerNo()), Customer::getCustomerNo, query.getCustomerNo())
            .or().eq(StrUtil.isBlank(query.getPhoneNo()), Customer::getPhoneNo, query.getPhoneNo())
            .or().eq(StrUtil.isBlank(query.getEmail()), Customer::getEmail, query.getEmail()).count();
        AssertUtil.assertThrow("客户信息已存在" + JSONUtil.toJsonStr(query), count > 0 && Objects.equals(throwOnEnum, AssertEnum.NOT_FOUND));
        AssertUtil.assertThrow("客户信息不存在" + JSONUtil.toJsonStr(query), count == 0 && Objects.equals(throwOnEnum, AssertEnum.FOUND));
        return count > 0;
    }

    @Override
    public CustomerBO getCustomer(CustomerGetQuery query) {
        if (ObjFieldUtil.isAllNullFields(query, ObjFieldUtil.ConvertNull.BLANK)) {
            return null;
        }
        Customer entity = MapperUtil.nf().map(query, Customer.class);
        Customer customer = this.lambdaQuery().setEntity(entity).one();
        CustomerBO customerBO = MapperUtil.nf().map(customer, CustomerBO.class);
        this.setProperties(ListUtil.list(false, customerBO));
        return customerBO;
    }

    @Override
    public IPage<CustomerBO> pageCustomers(PageParam pageParam) {
        if (pageParam == null) pageParam = new PageParam(false);
        Page<Customer> customerPage = this.lambdaQuery().orderByDesc(Customer::getCreateTime).page(pageParam.convert());
        IPage<CustomerBO> customerBOPage = PageUtils.convert(customerPage, CustomerBO.class);
        this.setProperties(customerBOPage.getRecords());
        return customerBOPage;
    }

    @Override
    public IPage<CustomerBO> pageCustomers(PageParam pageParam,
                                           String fuzzyString,
                                           List<String> levelIds,
                                           Boolean isOpen,
                                           List<String> channelTypes,
                                           List<String> userIds,
                                           List<String>  channelIds) {
        if (StringUtils.isBlank(fuzzyString) &&
            CollectionUtils.isEmpty(levelIds) &&
            isOpen == null &&
            CollectionUtils.isEmpty(channelTypes) &&
            CollectionUtils.isEmpty(userIds)&&CollectionUtils.isEmpty(channelIds)) {
            return this.pageCustomers(pageParam);
        }
        if (pageParam == null) {
            pageParam = PageParam.getBigPageParam();
        }
        IPage<Customer> customerPage = this.baseMapper.queryCustomers(pageParam.<Customer>convert(), fuzzyString, levelIds, isOpen, channelTypes, userIds,channelIds);
        IPage<CustomerBO> customerBOPage = PageUtils.convert(customerPage, CustomerBO.class);
        this.setProperties(customerBOPage.getRecords());
        return customerBOPage;
    }


    @Override
    public IPage<CustomerBO> efficientPageCustomers(PageParam pageParam) {
        if (pageParam == null) {
            pageParam = PageParam.getBigPageParam();
        }
        List<Customer> customers = this.baseMapper.efficientPageCustomers(pageParam.getCurrent() - 1, pageParam.getSize()
        );
        List<CustomerBO> customerBOS = MapperUtil.nf().mapAsList(customers, CustomerBO.class);
        Page<CustomerBO> customerBOPage = new Page<>();
        customerBOPage.setRecords(customerBOS);
        return customerBOPage;
    }

    @Override
    public List<String> listCustomer2UserId(String fuzzyString) {
        if (StrUtil.isBlank(fuzzyString)) return new ArrayList<>();
        List<Customer> customers = this.list(Wrappers.<Customer>lambdaQuery().select(Customer::getUserId).like(Customer::getCustomerName, fuzzyString).or().like(Customer::getPhoneNo, fuzzyString).or().like(Customer::getEmail, fuzzyString));
        return customers.stream().map(Customer::getUserId).collect(Collectors.toList());
    }

    @Override
    public List<CustomerBO> listCustomerByEmails(Collection<String> emails) {
        if (CollectionUtil.isEmpty(emails)) {
            return new ArrayList<>();
        }
        List<Customer> list = super.lambdaQuery().in(Customer::getEmail, emails).list();
        return MapperUtil.nf().mapAsList(list, CustomerBO.class);
    }

    @Override
    public List<String> listCustomer2UserId(String fuzzyString, List<String> levelIds, Date startTime, Date endTime, Boolean isOpen, SortEnum sortEnum) {
        if (StrUtil.isBlank(fuzzyString) &&
            CollectionUtils.isEmpty(levelIds) &&
            (startTime == null || endTime == null) &&
            isOpen == null) {
            return new ArrayList<>();
        }

        List<Customer> customers = this.list(Wrappers.<Customer>lambdaQuery().select(Customer::getUserId)
            .in(CollectionUtils.isNotEmpty(levelIds), Customer::getCustomerLevel, levelIds) // 客户等级
            .and(isOpen != null, condition -> {
                if (isOpen) { // 是否开通
                    condition.isNotNull(Customer::getUserName).ne(Customer::getUserName, "");
                } else {
                    condition.isNull(Customer::getUserName).or().eq(Customer::getUserName, "");
                }
            })
            .and(StrUtil.isNotBlank(fuzzyString), condition -> condition
                .like(StrUtil.isNotBlank(fuzzyString), Customer::getCustomerName, fuzzyString).or()
                .like(StrUtil.isNotBlank(fuzzyString), Customer::getPhoneNo, fuzzyString).or()
                .like(StrUtil.isNotBlank(fuzzyString), Customer::getEmail, fuzzyString)) // 模糊条件
            .and(Objects.nonNull(startTime) && Objects.nonNull(endTime), condition -> condition
                .ge(Customer::getCreateTime, startTime).le(Customer::getCreateTime, endTime)) // 注册时间
            .orderByDesc(sortEnum != null && sortEnum == SortEnum.DESC, Customer::getCreateTime)
            .orderByAsc(sortEnum != null && sortEnum == SortEnum.ASC, Customer::getCreateTime));

        return customers.stream().map(Customer::getUserId).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CustomerBO registerCustomer(CustomerAddQuery customer2Add, UserRightsProp rights2Add) {
        Customer customer = MapperUtil.nf().map(customer2Add, Customer.class);
        // 保存客户信息
        this.saveCustomer(customer);
        // 增加用户权益信息
        UserRightsBO userRightsBO = MapperUtil.nf().map(rights2Add, UserRightsBO.class);
        if (ObjFieldUtil.isAllNullFields(userRightsBO, ObjFieldUtil.ConvertNull.NONE)) {
            this.userRightsService.addUserRights(customer.getUserId(), customer.getCustomerLevel());
        } else {
            userRightsBO.setUserId(customer.getUserId())
                .setLevelId(customer.getCustomerLevel());
            this.userRightsService.addUserRights(userRightsBO);
        }
        // licenseUser
        if (Objects.isNull(rights2Add) || Objects.isNull(rights2Add.getLicenseUserList())) {
            this.licenseUserService.batchUpdateLicenseUser(customer.getUserId(), customer.getCustomerLevel());
        } else {
            this.licenseUserService.batchUpdateLicenseUser(customer.getUserId(), rights2Add.getLicenseUserList());
        }
        // 更新客户与工作人员关系
        this.addOrUpdateCustomerRef(customer.getUserId(), customer2Add.getCustomerRefQueries());
        // 增加销售/客服关联
        this.addCustomerRefByChannel(customer.getUserId(), customer.getChannelId());
        return MapperUtil.nf().map(customer, CustomerBO.class);
    }

    @Override
    @Transactional
    public CustomerBO createSaasUser(String customerNo, UserAccountAddQuery userAccount2Add) {
        AssertUtil.assertThrow("创建云平台账户失败,客户编号不能为空", StrUtil.isBlank(customerNo));
        AssertUtil.assertThrow("创建云平台账户失败,手机和邮箱不可同时为空", StrUtil.isAllBlank(userAccount2Add.getPhoneNo(), userAccount2Add.getEmail()));
        CustomerBO customer = this.getCustomer(new CustomerGetQuery().setCustomerNo(customerNo));
        AssertUtil.assertThrow("创建云平台账户失败,客户信息不存在", Objects.isNull(customer));
        UserAccountBO account = userAccountService.getAccount(new UserAccountGetQuery().setUserName(customer.getUserName()));
        AssertUtil.assertThrow("创建云平台账户失败,该客户已创建了云平台账户", Objects.nonNull(account));

        userAccount2Add.setUserId(customer.getUserId());
        // 注册云平台账户
        account = userAccountService.addAccount(userAccount2Add, false);
        // 更新客户信息用户名
        this.lambdaUpdate().eq(Customer::getPid, customer.getPid()).set(Customer::getUserName, account.getUserName()).update();
        customer.setUserName(account.getUserName());
        return customer;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateCustomer(CustomerUpdateQuery customer2Update, UserRightsProp rights2Update) {
        ObjFieldUtil.isAllNullFields(customer2Update, ObjFieldUtil.ConvertNull.BLANK);
        Customer entity2Update = MapperUtil.nf().map(customer2Update, Customer.class);

        CustomerGetQuery getQuery = new CustomerGetQuery();
        if (StrUtil.isNotBlank(entity2Update.getPid())) {
            getQuery.setPid(entity2Update.getPid());
        } else if (StrUtil.isNotBlank(entity2Update.getCustomerNo())) {
            getQuery.setCustomerNo(entity2Update.getCustomerNo());
        } else if (StrUtil.isNotBlank(entity2Update.getUserId())) {
            getQuery.setUserId(entity2Update.getUserId());
        } else {
            throw DefaultSaasException.build("更新ID为空").status(HttpStatus.BAD_REQUEST);
        }
        CustomerBO originCustomer = this.getCustomer(getQuery);
        AssertUtil.assertThrow("待更新的客户信息不存在：" + entity2Update.getPid(), Objects.isNull(originCustomer));
        entity2Update.setPid(originCustomer.getPid());
        // 更新客户信息
        boolean update = this.updateCustomer(entity2Update);
        if (!update)
            return false;

        // 当有等级更新
        if (!ObjFieldUtil.isAllNullFields(rights2Update, ObjFieldUtil.ConvertNull.NONE)) {
            UserRightsUpdateQuery userRightsUpdateQuery = MapperUtil.nf().map(rights2Update, UserRightsUpdateQuery.class);
            userRightsUpdateQuery.setUserId(originCustomer.getUserId());
            userRightsUpdateQuery.setLevelId(entity2Update.getCustomerLevel());
            this.userRightsService.updateUserRights(userRightsUpdateQuery, false);
            this.licenseUserService.batchUpdateLicenseUser(originCustomer.getUserId(), rights2Update.getLicenseUserList());
        } else if (StrUtil.isNotBlank(entity2Update.getCustomerLevel()) &&
            !Objects.equals(entity2Update.getCustomerLevel(), originCustomer.getCustomerLevel())) {
            this.userRightsService.updateUserRights(originCustomer.getUserId(), entity2Update.getCustomerLevel(), false);
            this.licenseUserService.batchUpdateLicenseUser(originCustomer.getUserId(), entity2Update.getCustomerLevel());
        }

        // 更新手机或邮箱
        if (Objects.nonNull(entity2Update.getPhoneNo()) && !Objects.equals(entity2Update.getPhoneNo(), originCustomer.getPhoneNo()) ||
            Objects.nonNull(entity2Update.getEmail()) && !Objects.equals(entity2Update.getEmail(), originCustomer.getEmail())) {
            UserAccountUpdateQuery userAccountUpdateQuery = new UserAccountUpdateQuery();
            userAccountUpdateQuery.setUserId(originCustomer.getUserId())
                .setEmail(entity2Update.getEmail())
                .setPhoneNo(entity2Update.getPhoneNo());
            userAccountService.updateAccount(userAccountUpdateQuery, false);
        }

        // 更新客户与工作人员关系
        this.addOrUpdateCustomerRef(originCustomer.getUserId(), customer2Update.getCustomerRefQueries());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCustomerByNo(String customerNo) {
        CustomerBO customer = this.getCustomerByNo(customerNo);
        if (customer == null)
            return;
        this.removeById(customer.getPid());
        this.userAccountService.deleteAccount(customer.getUserId());
        this.userTripartiteService.unBoundByUserId(customer.getUserId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCustomerByUserId(String userId) {
        CustomerBO customer = this.getCustomerByUserId(userId);
        if (customer == null) {
            return;
        }
        this.removeById(customer.getPid());
        this.userAccountService.deleteAccount(customer.getUserId());
        this.userTripartiteService.unBoundByUserId(customer.getUserId());
    }

    @Override
    public IPage<CustomerBO> listUnBoundCustomerList(PageParam pageParam) {
        IPage<Customer> customerPage = this.baseMapper.listUnBoundCustomerList(pageParam.convert());
        return PageUtils.convert(customerPage, CustomerBO.class);
    }

    @Override
    public Integer countByChannelId(List<String> channelIds) {
        if (CollectionUtils.isEmpty(channelIds)) return 0;
        return this.count(Wrappers.<Customer>lambdaQuery().in(Customer::getChannelId, channelIds));
    }

    @Override
    public List<CustomerBO> getCustomersByUser(List<String> userIds) {
        if (CollectionUtil.isNotEmpty(userIds)) {
            List<Customer> list = this.lambdaQuery().in(Customer::getUserId, userIds).list();
            return MapperUtil.nf().mapAsList(list, CustomerBO.class);
        }
        return new ArrayList<>();
    }

    private Customer saveCustomer(Customer customer) {
        this.existCustomer(new CustomerGetQuery().setCustomerNo(customer.getCustomerNo()), AssertEnum.NOT_FOUND);
        this.checkLevelId2Save(customer);
        this.setChannelDesc(customer);
        // 持久化数据
        customer.setPid(SnowFlakeUtil.nextIdStr());
        if (StrUtil.isBlank(customer.getUserId()))
            customer.setUserId(SnowFlakeUtil.nextIdStr());
        if (StringUtils.isBlank(customer.getCustomerNo()))
            customer.setCustomerNo(SnowFlakeUtil.nextIdStr());
        customer.setStatus(1);
        this.save(customer);
        return customer;
    }

    private boolean updateCustomer(Customer customer) {
        AssertUtil.assertThrow("PID为空", StrUtil.isBlank(customer.getPid()));
        this.checkLevelId2Update(customer, null);
        // 更新客户信息
        return this.updateById(customer);
    }

    /**
     * 通过注册渠道增加客户与工作人员关系
     */
    private void addCustomerRefByChannel(String userId, String channelId) {
        CustomerRefBO customerRefBO = new CustomerRefBO();
        // 专属推广销售
        customerRefBO.setRelation(SysDictKeyEnum.RELATION_2.getKey());
        // 检查channelId是否是销售id或者销售手机号码
        StaffBO staffBo = staffService.getById(channelId);
        if (Objects.isNull(staffBo))
            staffBo = staffService.queryByPhoneNo(channelId);
        if (Objects.isNull(staffBo)) {
            staffBo = staffService.getDefaultStaffInfo();
            customerRefBO.setRelation(SysDictKeyEnum.RELATION_1.getKey()); // 专属客服
        }
        customerRefBO.setStaffId(staffBo.getPid());
        customerRefBO.setUserId(userId);
        // 查找是否已有数据
        customerRefService.add(customerRefBO);
    }

    /**
     * 更新客户与工作人员关系
     */
    private void addOrUpdateCustomerRef(String userId, List<StaffCustomerRefQuery> customerRefQueries) {
        if (CollectionUtil.isEmpty(customerRefQueries)) return;
        // 删除所有
        customerRefService.deleteByUserId(userId);
        List<CustomerRefBO> customerRefBOS = new ArrayList<>();
        customerRefQueries.forEach(customerRef -> {
            StaffBO staffBO = staffService.getById(customerRef.getStaffId());
            if (Objects.isNull(staffBO)) return; // 为空跳过
            CustomerRefBO customerRefBO = new CustomerRefBO();
            customerRefBO.setPid(String.valueOf(SnowFlakeUtil.nextId()));
            customerRefBO.setUserId(userId);
            customerRefBO.setRelation(customerRef.getRelation());
            customerRefBO.setStaffId(customerRef.getStaffId());
            customerRefBOS.add(customerRefBO);
        });

        if (CollectionUtil.isNotEmpty(customerRefBOS))
            // 添加所有
            customerRefService.addBatch(customerRefBOS);
    }

    private void checkLevelId2Save(Customer customer) {
        // 未指定levelId
        if (StrUtil.isBlank(customer.getCustomerLevel())) {
            String levelId = this.getLevelIdByPhoneOrEmail(customer.getPhoneNo(), customer.getEmail());
            log.debug("客户信息登记，获取levelId: {}", levelId);
            customer.setCustomerLevel(levelId);
            return;
        }
        // 检查levelId有效性
        boolean levelExists = customerLevelService.existCustomerLevel(
            new CustomerLevelGetQuery().setLevelId(customer.getCustomerLevel()), AssertEnum.IGNORE);
        if (levelExists) return;
        log.error("客户({})信息登记，等级({})不存在，已重置为默认等级.", customer.getCustomerNo(), customer.getCustomerLevel());
        customer.setCustomerLevel(propertyService.getPropertyValue(SysDictKeyEnum.DEFAULT_LEVEL_ID, "1"));
    }

    private void checkLevelId2Update(Customer update, Customer origin) {
        if (origin == null) {
            origin = super.getById(update.getPid());
        }
        AssertUtil.assertThrow("待更新客户信息不存在", Objects.isNull(origin));
        // 指定了更新的levelId
        if (StrUtil.isNotBlank(update.getCustomerLevel())) {
            // 检查levelId有效性
            log.debug("客户信息更新，levelId: {}", update.getCustomerLevel());
            boolean levelExists = customerLevelService.existCustomerLevel(
                new CustomerLevelGetQuery().setLevelId(update.getCustomerLevel()), AssertEnum.IGNORE);
            if (!levelExists)
                update.setCustomerLevel(null);
            return;
        }
        // 未指定更新的levelId
        update.setCustomerLevel(null);
        // 动态levelId过程
        // 检查原等级是否为动态id
        CustomerLevelBO originLevel = customerLevelService.getLevelById(origin.getCustomerLevel());
        if (Objects.nonNull(originLevel)) {
            String dynamicLevels = propertyService.getPropertyValue(SysDictKeyEnum.DYNAMIC_LEVELS);
            if (!dynamicLevels.contains(originLevel.getLevelId())) {
                return;
            }
        }
        // 根据邮箱和手机获取等级ID
        if (StrUtil.isAllBlank(update.getPhoneNo(), update.getEmail()))
            return;
        if (StrUtil.isBlank(update.getPhoneNo()))
            update.setPhoneNo(origin.getPhoneNo());
        if (StrUtil.isBlank(update.getEmail()))
            update.setEmail(origin.getEmail());
        String levelId2Update = this.getLevelIdByPhoneOrEmail(update.getPhoneNo(), update.getEmail());
        if (!Objects.equals(levelId2Update, origin.getCustomerLevel())) {
            update.setCustomerLevel(levelId2Update);
        }
    }

    private String getLevelIdByPhoneOrEmail(String phoneNo, String email) {
        return isEduEmail(email) ? propertyService.getPropertyValue(SysDictKeyEnum.EDU_LEVEL_ID) :
            StrUtil.isNotBlank(phoneNo) ? propertyService.getPropertyValue(SysDictKeyEnum.PHONE_LEVEL_ID) :
                propertyService.getPropertyValue(SysDictKeyEnum.EMAIL_LEVEL_ID);
    }

    private boolean isEduEmail(String email) {
        if (StrUtil.isBlank(email))
            return false;
        String propertyValue = propertyService.getPropertyValue(SysDictKeyEnum.EDU_EMAIL_SUFFIX);
        String[] split = propertyValue.split("[;,]");
        for (String suffix : split) {
            if (email.endsWith(suffix))
                return true;
        }
        return false;
    }

    private void setChannelDesc(Customer customer) {
        // 获取渠道描述
        String channelType = customer.getChannelType();
        String channelId = customer.getChannelId();
        String channelDesc = customer.getChannelDesc();
        String propertyValue = propertyService.getPropertyValue(SysDictModuleEnum.CHANNEL_SERVICE.getModule(), channelType, "");
        log.debug("客户({})信息登记，渠道：{}:{}", customer.getCustomerNo(), customer.getChannelType(), customer.getChannelId());

        if (StrUtil.isNotBlank(channelDesc))
            return;
        IChannelCommonService channelCommonService;
        try {
            channelCommonService = SpringContextUtils.getBean(propertyValue, IChannelCommonService.class);
        } catch (Exception e) {
            channelCommonService = channelService -> "";
            log.error("找不到渠道{}对应的业务实现", propertyValue);
        }
        channelDesc = channelCommonService.getChannelDesc(channelId);
        customer.setChannelDesc(channelDesc);
    }

    private void setProperties(List<CustomerBO> customerBOList) {
        for (CustomerBO customerBO : customerBOList) {
            if (customerBO == null)
                continue;
            // customerLevel
            if (StringUtils.isNotBlank(customerBO.getCustomerLevel())) {
                CustomerLevelBO customerLevelBO = customerLevelService.getLevelById(customerBO.getCustomerLevel());
                if (customerLevelBO != null) {
                    customerBO.setCustomerLevelText(customerLevelBO.getLevelText());
                }
            }
            // set user register date
            Optional<UserAccountBO> accountOptional = Optional.ofNullable(userAccountService.getAccount(customerBO.getUserId()));
            customerBO.setRegisterDate(DateUtil.format(accountOptional.map(UserAccountBO::getRegisteredDate).orElse(null),"yyyy-MM-dd HH::mm::SS"));

            // set hpcAccount count
            int hpcAccountAmount = 0;
            hpcAccountAmount = this.baseMapper.getAllotHpcCountByUserId(customerBO.getUserId());
            customerBO.setHpcAccountAmount(hpcAccountAmount);

            // 设置客户与工作人员信息
            customerBO.setCustomerStaffBOS(new ArrayList<>());
            // 获取客户的专属销售和专属客服信息
            List<CustomerStaffBO> customerStaffBOS = customerBO.getCustomerStaffBOS();

            List<CustomerRefBO> customerRefBOS = StrUtil.isNotBlank(customerBO.getUserId()) ?
                customerRefService.search(new CustomerRefBO().setUserId(customerBO.getUserId()))
                : new ArrayList<>();
            if (CollectionUtil.isNotEmpty(customerRefBOS)) {
                customerRefBOS.forEach(customerRefBO -> {
                    StaffBO staffBO = staffService.getById(customerRefBO.getStaffId());

                    if (Objects.isNull(staffBO)) {
                        staffBO = staffService.getDefaultStaffInfo();
                    }

                    CustomerStaffBO staffDto = MapperUtil.nf().map(staffBO, CustomerStaffBO.class);
                    // 设置工作人员与用户之间的关系
                    staffDto.setRelation(customerRefBO.getRelation());

                    String propertyValue = propertyService.getPropertyValue(SysDictModuleEnum.RELATION.getModule(),
                        customerRefBO.getRelation(), SysDictKeyEnum.RELATION_1.getText());
                    staffDto.setRelationName(propertyValue);

                    customerStaffBOS.add(staffDto);
                });
            } else {
                StaffBO staffBO = staffService.getDefaultStaffInfo();
                CustomerStaffBO staffDto = MapperUtil.nf().map(staffBO, CustomerStaffBO.class);
                staffDto.setRelation(SysDictKeyEnum.RELATION_1.getKey());
                customerStaffBOS.add(staffDto);
            }

            // 设置渠道名称
            String channelType = customerBO.getChannelType();
            String propertyValue = propertyService.getPropertyValue(SysDictModuleEnum.CHANNEL.getModule(), channelType, "未知渠道");
            customerBO.setChannelName(propertyValue);

        }
    }

    @Override
    public IPage<CustomerBO> listCustomerByNotInUserIdAndFuzzy(PageParam pageParam, List<String> userIds, String fuzzy, String keyword) {
        return PageUtils.convert(this.page(pageParam.convert(), Wrappers.<Customer>lambdaQuery()
            .notIn(Customer::getUserId, userIds).ne(Customer::getUserName, "")
            .and(StrUtil.isNotBlank(fuzzy), l ->
                l.likeRight(Customer::getUserName, fuzzy).or()
                    .likeRight(Customer::getEmail, fuzzy).or()
                    .likeRight(Customer::getCustomerName, fuzzy).or()
                    .likeRight(Customer::getPhoneNo, fuzzy))
            .and(StrUtil.isNotBlank(keyword), l ->
                l.eq(Customer::getUserName, keyword).or()
                    .eq(Customer::getEmail, keyword).or()
                    .eq(Customer::getCustomerName, keyword).or()
                    .eq(Customer::getPhoneNo, keyword))
        ), CustomerBO.class);
    }

    @Override
    public IPage<CustomerBO> listCustomerByInUserIdAndFuzzy(PageParam pageParam, List<String> userIds, String fuzzy, String keyword) {
        return PageUtils.convert(this.page(pageParam.convert(), Wrappers.<Customer>lambdaQuery()
            .in(Customer::getUserId, userIds)
            .and(StrUtil.isNotBlank(fuzzy), l ->
                l.likeRight(Customer::getUserName, fuzzy).or()
                    .likeRight(Customer::getEmail, fuzzy).or()
                    .likeRight(Customer::getCustomerName, fuzzy).or()
                    .likeRight(Customer::getPhoneNo, fuzzy))
            .and(StrUtil.isNotBlank(keyword), l ->
                l.eq(Customer::getUserName, keyword).or()
                    .eq(Customer::getEmail, keyword).or()
                    .eq(Customer::getCustomerName, keyword).or()
                    .eq(Customer::getPhoneNo, keyword))
        ), CustomerBO.class);
    }

    @Override
    public IPage<CustomerBO> listCustomerTrialList(PageParam pageParam, String fuzzy) {
        if (StrUtil.isBlank(fuzzy)) {
            return new Page<>();
        }
        return this.baseMapper.listCustomerTrialList(pageParam.convert(), fuzzy);
    }

    @Override
    public List<UserRegisterBO> findByUserIds(List<String> userIds) {
        if (CollectionUtil.isEmpty(userIds)) {
            return Collections.emptyList();
        }
        List<Customer> list = this.lambdaQuery().in(Customer::getUserId, userIds)
            .orderByDesc(Customer::getCreateTime)
            .list();
        if (CollectionUtil.isNotEmpty(list)) {
            List<UserRegisterBO> userRegisterBOS = MapperUtil.nf().mapAsList(list, UserRegisterBO.class);
            return userRegisterBOS;
        }
        return Collections.emptyList();
    }

    @Override
    public int getCustomerHpcCount(String userId) {
        return this.baseMapper.getAllotHpcCountByUserId(userId);
    }
}
